package connection;

import java.net.InetSocketAddress;
import java.security.PrivateKey;
import java.security.PublicKey;

import javax.crypto.SecretKey;

import messages.CipheredMessage;
import messages.SecureMessage;
import security.crypto.SimmEncryption;
import utils.Serialization;
import connection.exception.ConnectionResetException;

public abstract class TCPSecureSocket {

	protected final boolean _bypass = false;

	protected TCPSocket _tcpSocket;

	protected boolean _secureChannelEstablished;
	
	protected boolean _establishingSecureChannel;

	protected SecretKey _simSessionKey;
	
	protected PublicKey _remotePublicKey;
	
	protected PrivateKey _privateKey;
	
	protected Object _channelLastMessage;
	
	protected String _endpointId;
	
	protected String _remoteEndpointId;
	
	protected String _lastReceivedMessageTS = "0";
	
	protected enum UserPassProtocolPhases{
		WaitingSessionKey
	};
	
	protected enum CcProtocolPhases{
		WaitingSessionKey, WaitingAuthNounce, WaitingAuthNounceAnswer
	};
	
	protected enum CertificateProtocolPhases{
		WaitingSessionKey, WaitingServerChallenge
	};
	
	protected enum ChallengePhases{
		WaitingClientChallenge, WaitingChallengePair, WaitingServerChallengeAnswer
	}
	
	public enum EstablishmentModes{UsernamePassword, CitizenCard, DigitalCertificates};
	
	public Object receive() throws ConnectionResetException{
		
		Object obj = _tcpSocket.receive();
		
		if(obj== null)
			return null;

		if(_bypass || _establishingSecureChannel)
			return obj;
		else if(!obj.getClass().getSimpleName().equals("CipheredMessage")){
			return null;
		}
		
		String cipheredString = ((CipheredMessage)obj).getCipheredMessage();
		String secureMessageString = SimmEncryption.decipherString(cipheredString, _simSessionKey);
		SecureMessage secureMessage = (SecureMessage) Serialization.Deserialize(secureMessageString.getBytes());
		
		boolean validMessage = secureMessage.validateMessage(_lastReceivedMessageTS, _remoteEndpointId, _endpointId, _remotePublicKey);
		
		if(validMessage){
			_lastReceivedMessageTS = secureMessage.getTimestamp();
			return secureMessage.getObject();
		}
		else
			return null;

	}
	public void send(Object obj) throws ConnectionResetException{
		if(_bypass || _establishingSecureChannel)
			_tcpSocket.send(obj);
		else{
			_channelLastMessage = obj;
			
			SecureMessage secureMessage = new SecureMessage(obj, _endpointId, _remoteEndpointId, _privateKey);
			String secureMessageString = Serialization.SerializeAsXml(secureMessage);
			String cipheredString = SimmEncryption.cipherString(secureMessageString, _simSessionKey);
			
			CipheredMessage cipheredMessage = new CipheredMessage(cipheredString);
			
			_tcpSocket.send(cipheredMessage);
			
			System.out.println();
		}
			return;
	}

	public boolean isConnected(){
		return _tcpSocket.isConnected();
	}

	public boolean isSecureChannelEstablished(){
		if(_bypass)
			return true;
		else
			return _secureChannelEstablished;
	}
	
	public InetSocketAddress getSocketAddress(){
		return _tcpSocket.getRemoteSocketAddress();
	}
}
